package applications.geststation;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import gestionColis.AdresseNonDesservieException;
import gestionColis.AucuneCasierDispoException;
import gestionColis.GestStationPOA;
import gestionColis.InfoAdherent;
import gestionColis.InfoColis;
import gestionColis.InfoStation;
import gestionColis.Station;
import gestionColis.StationInconnueException;
import gestionColis.StationNonConfigureeException;

/**
 * Gestion des stations
 * @author simongrevin
 *
 */
public class GestStationImpl extends GestStationPOA {

	/**
	 * Les IOR des stations mappés sur leur id
	 */
	private Map<String, Station> iorStations = new HashMap<String, Station>();
	
	/**
	 * Les objets métiers Station
	 */
	private List<StationMetier> stations = new ArrayList<StationMetier>();
	
	/** Valeur du tarif élevé */
	private final static double TARIF_ELEVE = 3;
	
	/** Valeur du tarif élevé */
	private final static double TARIF_MOYEN = 2;
	
	/** Valeur du tarif élevé */
	private final static double TARIF_BAS = 1;
	
	
	/**
	 * A partir du code postal de l'adhérent, récupération de sa station d'appartenance
	 */
	@Override
	public InfoStation recupererStationAdhesion(InfoAdherent adherent)
			throws AdresseNonDesservieException {
		
		// information sur la station d'appartenance (idStation)
		InfoStation infoStation = new InfoStation();
		
		boolean codePostalConnu = false;
		
		// je regarde le cp, et j'en déduis l'idStation de cet adhérent
		for (StationMetier station : stations) {
			if (station.getCodePostal().equals(adherent.codePostal)) {
				infoStation.idStation = station.getIdStation();
				codePostalConnu = true;
			}
		}
		
		// aucune station trouvée pour ce code postal
		if (!codePostalConnu) {
			throw new AdresseNonDesservieException();
		}
		
		return infoStation;
	}

	/**
	 * Calcul le cout de transport à partir de l'emplacement des deux stations
	 */
	@Override
	public double calculerCoutTransport(InfoStation depart, InfoStation arrivee)
			throws StationInconnueException {
		
		double tarif = 0;
		
		StationMetier stationDep = new StationMetier();
		StationMetier stationArr = new StationMetier();
		
		// on récupère les stations métiers correspondantes
		for (StationMetier station : stations){
			if (station.getIdStation().equals(depart.idStation)) {
				stationDep = station;
			}
			if (station.getIdStation().equals(arrivee.idStation)) {
				stationArr = station;
			}
		}
		
		// Calcul du tarif en fonction de l'éloignement
		if (stationArr.getRegion().getIdRegion().equals(stationDep.getRegion().getIdRegion())) {
			// les stations sont dans la même région
			if (isStationsVoisines(stationDep, stationArr)) {
				// les stations sont voisines : prix bas
				tarif = TARIF_BAS;
			} else {
				// les stations ne sont pas voisines : prix moyen
				tarif = TARIF_MOYEN;
			}
		} else {
			// les deux stations ne sont pas dans la même région : prix cher
			tarif = TARIF_ELEVE;
		}
			
		
		return tarif;
	}

	/**
	 * Retransmission d'une demande de réservation d'un casier auprès
	 * de la station d'arrivée
	 * A partir de l'id de la station d'arrivée
	 * @throws StationNonConfigureeException 
	 * @throws AucuneCasierDispoException 
	 */
	@Override
	public void demandeReservationCasier(InfoStation arrivee, InfoColis colis)
			throws StationInconnueException, AucuneCasierDispoException {
		
		// on récupère l'IOR de la station d'arrivée à partir de l'idStation
		Station station = iorStations.get(arrivee.idStation);
		
		if (station == null) {
			throw new StationInconnueException();
		}
		
		// si aucun casier dispo, l'exception AucuneCasierDispoException sera "re-thrown"
		station.reserverCasier(colis);
	}
	
	/**
	 * Enregistrement de l'IOR d'une nouvelle Station
	 * La station doit communiquer son code postal pour identification
	 * La station doit déjà être configurée dans la BD de 
	 * @throws StationNonConfigureeException 
	 */
	@Override
	public void enregistrerStation(Station iorStation, String codePostal) throws StationNonConfigureeException {
		
		/*
		 *  les stations doivent être enregistrées en BD avant quelles 
		 *  ne s'enregistrent en mode IOR
		 */
		boolean stationConfiguree = false;
		
		// on parcourt toutes les stations et on cherche celle correspondant à ce code postal
	    for (StationMetier station : stations) {
	    	if (station.getCodePostal().equals(codePostal)) {
	    		// on enregistre l'ior de la station en le mappant sur l'id de la station
	    	    iorStations.put(station.getIdStation(), iorStation);
	    	    stationConfiguree = true;
	    	}
	    }
	    
	    if (!stationConfiguree) {
	    	throw new StationNonConfigureeException();
	    }
	}
	
	/**
	 * Vérifie si la station d'arrivée fait partie des stations voisines de la station de départ
	 * @param stationDep
	 * @param stationArr
	 * @return true or false
	 */
	private boolean isStationsVoisines(StationMetier stationDep, StationMetier stationArr) {
		boolean voisines = false;
		// parcours des stations voisines de stationDep
		for (StationMetier stationVoisine : stationDep.getStationsVoisines()) {
			// si station d'arrivée est voisine 
			if(stationArr.getIdStation().equals(stationVoisine.getIdStation())) {
				voisines = true;
			}
		}
		return voisines;
	}
}
